package com.mtr.databoard.application.screens;


import com.mtr.databoard.application.EntityResultDto;
import com.mtr.databoard.application.PagedResultDto;
import com.mtr.databoard.application.screens.dto.*;
import com.mtr.databoard.common.linqlist.LinqList;
import com.mtr.databoard.domain.components.ViewComponent;
import com.mtr.databoard.domain.resources.ResourceManager;
import com.mtr.databoard.domain.screens.IScreenRepository;
import com.mtr.databoard.domain.screens.Screen;
import com.mtr.databoard.domain.screens.ScreenComponent;
import com.mtr.databoard.domain.screens.ScreenManager;
import org.bson.types.Binary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import java.util.UUID;

@Controller
@RequestMapping("screen")
public class ScreenApplication {
    private ScreenManager screenManager;
    private IScreenRepository screenRepository;
    private ResourceManager resourceManager;

    public ScreenApplication(@Autowired ScreenManager screenManager, @Autowired IScreenRepository screenRepository, ResourceManager resourceManager) {
        this.screenManager = screenManager;
        this.screenRepository = screenRepository;
        this.resourceManager = resourceManager;
    }
    @GetMapping("/getall")
    @ResponseBody
    public EntityResultDto<PagedResultDto<GetAllScreenDto>> getAllScreens() {
        var screens = screenRepository.findAll();
        var output =LinqList.parse(screens).select(s->new GetAllScreenDto(s.getId(),s.getName(),s.getDescription(),s.getCover())).toList();
        return EntityResultDto.newSuccessResult(new PagedResultDto<>(screens.size(), output));
    }

    @GetMapping("/get/{id}")
    @ResponseBody
    public EntityResultDto<Screen> getScreen(@PathVariable UUID id) {
        if (!screenRepository.existsById(id)) return EntityResultDto.newErrorResult(null);
        var screen = screenRepository.findById(id).get();
        if(screen.getComponents()!=null)
            screen.getComponents().sort((c1,c2)->c1.getOrder());
        return EntityResultDto.newSuccessResult(screen);
    }

    @PostMapping("/create")
    @ResponseBody
    public EntityResultDto<Screen> createScreen(@RequestBody CreateScreenInput input) throws IOException {
        var screen = screenManager.createScreen(input.getName());
        return EntityResultDto.newSuccessResult(screen);
    }

    @PostMapping("/copy/{id}")
    @ResponseBody
    public EntityResultDto<Screen> copyScreen(@PathVariable UUID id) throws IOException, CloneNotSupportedException {
        var screen = screenManager.copyScreen(id);
        return EntityResultDto.newSuccessResult(screen);
    }

    @PutMapping("/updateBaseInfo")
    @ResponseBody
    public EntityResultDto<String> updateScreenBaseInfo(@RequestBody UpdateScreenBaseInfoInput input) throws IOException {
        screenManager.updateScreenBaseInfo(input.getScreenId(),input.getName(),input.getDescription(),input.getCover());
        return EntityResultDto.newSuccessResult(null);
    }
    @PutMapping("/update")
    @ResponseBody
    public EntityResultDto<String> updateScreen(@RequestBody UpdateScreenInut input) throws IOException {
        screenManager.updateScreen(input.getId(),input.getName(),input.getWidth(),input.getHeight(),input.isAutoFit(),input.getComponents());
        return EntityResultDto.newSuccessResult(null);
    }

    @DeleteMapping("/delete/{id}")
    @ResponseBody
    public EntityResultDto<String> deleteScreen(@PathVariable UUID id) {
        screenManager.deleteScreen(id);
        return EntityResultDto.newSuccessResult(null);
    }


    @PostMapping("/copycomponent/{screenComponentId}")
    @ResponseBody
    public EntityResultDto<ScreenComponent> copyScreenComponent(@PathVariable UUID screenComponentId) throws IOException, CloneNotSupportedException {
        var component = screenManager.copyScreenComponent(screenComponentId);
        return EntityResultDto.newSuccessResult(component);
    }

    @PostMapping("/importcomponents")
    @ResponseBody
    public EntityResultDto<List<ScreenComponent>> importScreenComponents(@RequestBody ImportScreenComponentInput input) throws IOException, CloneNotSupportedException {
        var components = screenManager.importComponents(input.getViewComponentIds());
        return EntityResultDto.newSuccessResult(components);
    }

    @GetMapping("/resource/view/{screenId}/{viewId}/**")
    @ResponseBody
    public void getComponentResource(@PathVariable UUID screenId, @PathVariable UUID viewId, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        String resourcePath = request.getRequestURI().split(screenId.toString()+"/"+viewId.toString())[1];
        resourcePath = URLDecoder.decode(resourcePath, "utf-8");
        Binary content = resourceManager.getFileContent("screen", screenId.toString()+"/view/"+viewId.toString(), resourcePath);
        if (content == null) return;

        String fileName = new File(resourcePath).getName();

        response.setContentType("octet-stream");
        response.setHeader("Content-Disposition", ";filename=" + fileName);

        OutputStream os = null;
        try {
            os = response.getOutputStream();
            os.write(content.getData());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (Exception ex) {

            }
        }
    }


    @GetMapping("/preview/{id}")
    public String preview(@PathVariable UUID id, Model m) {
        if (!screenRepository.existsById(id)) return "screen/empty";
        Screen screen= screenRepository.findById(id).get();

//        for(var component:screen.getComponents())
//        {
//            if (component.getView()!=null&&component.getView().getHeadLinks() != null) {
//                component.getView().setHeadLinks(fillEnvironmentVariables(component.getView().getHeadLinks(),id,component));
//            }
//            if(component.getView().getCodes()!=null)
//                component.getView().setCodes(fillEnvironmentVariables(component.getView().getCodes(),id,component));
//        }
        var background = new LinqList<>(screen.getComponents()).firstOrDefault(c->c.getPosition().getBackgound());
        screen.setComponents(new LinqList<>(screen.getComponents()).toList(com->com.isShow()));
        if(background!=null)
            m.addAttribute("background", background);
        m.addAttribute("screen", screen);
        return "screen/preview";
    }

    @GetMapping("/preview/view/{screenId}/{viewId}")
    public String previewView(@PathVariable UUID screenId, @PathVariable UUID viewId, Model m) {
        if (!screenRepository.existsById(screenId)) return "screen/empty";
        Screen screen= screenRepository.findById(screenId).get();
        var linqComs = new LinqList<>(screen.getComponents());
        var component =linqComs.firstOrDefault(c->c.getId().equals(viewId));
        if(component==null) return "screen/empty";
        if (component.getView()!=null&&component.getView().getHeadLinks() != null) {
            component.getView().setHeadLinks(fillEnvironmentVariables(component.getView().getHeadLinks(),screenId,component));
        }
        if(component.getView().getCodes()!=null)
            component.getView().setCodes(fillEnvironmentVariables(component.getView().getCodes(),screenId,component));
        if(component.getView().getHtmlbody()!=null)
            component.getView().setHtmlbody(fillEnvironmentVariables(component.getView().getHtmlbody(),screenId,component));
        if(component.getView().getCustomerOptions()!=null)
            component.getView().getCustomerOptions().setValues(fillEnvironmentVariables(component.getView().getCustomerOptions().getValues(),screenId,component));
        m.addAttribute("component", component.getView());

        return "screen/viewComponent";
    }


    /**
     * 填充环境变量，替换实际值
     * @param content
     * @param component
     * @return
     */
    private String fillEnvironmentVariables(String content,UUID screenId,ScreenComponent component)
    {
        if(content==null||content.length()==0) return  content;
        //资源路径
        content = content.replaceAll("\\{filedir\\}", "/screen/resource/view/"+screenId.toString()+"/"+component.getView().getId().toString());
        //组件id
        content = content.replaceAll("\\{componentId\\}", component.getId().toString());
        content = content.replaceAll("\\{viewcode\\}", component.getView().getCode());
        content = content.replaceAll("\\{viewname\\}", component.getView().getCode());
        return content;
    };
}
